﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using mshtml;

namespace JWFW.Model.HtmlEditor
{
    /// <summary>
    /// Html编辑控件
    /// </summary>
    [Description("Provides a user control that allows the user to edit HTML page."), ClassInterface(ClassInterfaceType.AutoDispatch)]
    public partial class HtmlTextBoxWB : UserControl
    {
        /// <summary>
        /// 使用WebBrowser作为核心的Html编辑控件
        /// </summary>
        public HtmlTextBoxWB()
        {
            m_dataUpdate = 0;
            InitializeComponent();
            InitializeControls();
        }

        private Timer m_timer = new Timer();
        private string m_source = "";
        private bool m_isEnterBR = true;
        private int m_dataUpdate;
        private IHTMLDocument2 m_doc = null;
        private bool m_allowContentMenu = true;

        /// <summary>
        /// 是否处于更新状态
        /// </summary>
        private bool Updating
        {
            get
            {
                return m_dataUpdate != 0;
            }
        }
        /// <summary>
        /// 浏览器控件使用的核心文档对象
        /// </summary>
        private IHTMLDocument2 DOC
        {
            get {
                if (m_doc == null)
                {
                    if (webBrowserBody.Document == null)
                    {
                        webBrowserBody.DocumentText = ""; 
                    }
                    m_doc = webBrowserBody.Document.DomDocument as IHTMLDocument2;
                }
                return m_doc; 
            }
        }
        /// <summary>
        /// 获取或设置文本源码
        /// </summary>
        public override string Text
        {
            get
            {
                return webBrowserBody.DocumentText;
            }
            set
            {
                DOC.designMode = "Off";
                webBrowserBody.DocumentText = value;
                m_source = value;
                m_timer.Start();
            }
        }
        /// <summary>
        /// 获取图片路径集合
        /// </summary>
        public string[] Images
        {
            get
            {
                List<string> images = new List<string>();

                foreach (HtmlElement element in webBrowserBody.Document.Images)
                {
                    string image = element.GetAttribute("src");
                    if (!images.Contains(image))
                    {
                        images.Add(image);
                    }
                }

                return images.ToArray();
            }
        }
        /// <summary>
        /// 回车提交的是否是"br"
        /// </summary>
        public bool IsEnterBR
        {
            get { return m_isEnterBR; }
            set { m_isEnterBR = value; }
        }
        /// <summary>
        /// 是否显示默认的右键菜单
        /// </summary>
        public bool AllowContentMenu
        {
            get { return m_allowContentMenu; }
            set { m_allowContentMenu = value; }
        }

        /// <summary>
        /// 设置加载内容时是否播放声音，适合IE7以上
        /// </summary>
        /// <param name="enable"></param>
        public void SetLoadSound(bool enable)
        {
            CoInternetSetFeatureEnabled(INTERNETFEATURELIST.FEATURE_DISABLE_NAVIGATION_SOUNDS, SET_FEATURE_ON_PROCESS, !enable);
        }

        /// <summary>
        /// 初始化控件
        /// </summary>
        private void InitializeControls()
        {
            BeginUpdate();

            // Tool Bar
            foreach (FontFamily family in FontFamily.Families)
            {
                toolStripComboBoxName.Items.Add(family.Name);
            }

            toolStripComboBoxSize.Items.AddRange(FontSize.AllFontSize.ToArray());

            // Web Browser
            webBrowserBody.AllowWebBrowserDrop = false;
            webBrowserBody.IsWebBrowserContextMenuEnabled = false;
            webBrowserBody.DocumentText = string.Empty;
            webBrowserBody.PreviewKeyDown += new PreviewKeyDownEventHandler(webBrowserBody_PreviewKeyDown);
            webBrowserBody.GotFocus += new EventHandler(webBrowserBody_GotFocus);
            webBrowserBody.Document.Click += new HtmlElementEventHandler(webBrowserBody_DocumentClick);
            webBrowserBody.Document.Focusing += new HtmlElementEventHandler(webBrowserBody_DocumentFocusing);
            webBrowserBody.Document.ContextMenuShowing += new HtmlElementEventHandler(Document_ContextMenuShowing);
            webBrowserBody.Document.ExecCommand("EditMode", false, null);
            webBrowserBody.Document.ExecCommand("LiveResize", false, null);

            m_timer.Tick += new EventHandler(m_timer_Tick);
            m_timer.Interval = 1;

            EndUpdate();
        }
        /// <summary>
        /// 更新开始
        /// </summary>
        private void BeginUpdate()
        {
            ++m_dataUpdate;
        }
        /// <summary>
        /// 更新结束
        /// </summary>
        private void EndUpdate()
        {
            --m_dataUpdate;
        }
        /// <summary>
        /// 刷新工具栏
        /// </summary>
        public void RefreshToolBar()
        {
            BeginUpdate();

            try
            {
                mshtml.IHTMLDocument2 document = (mshtml.IHTMLDocument2)webBrowserBody.Document.DomDocument;

                toolStripComboBoxName.Text = document.queryCommandValue("FontName").ToString();
                toolStripComboBoxSize.SelectedItem = FontSize.Find((int)document.queryCommandValue("FontSize"));
                toolStripButtonBold.Checked = document.queryCommandState("Bold");
                toolStripButtonItalic.Checked = document.queryCommandState("Italic");
                toolStripButtonUnderline.Checked = document.queryCommandState("Underline");

                toolStripButtonNumbers.Checked = document.queryCommandState("InsertOrderedList");
                toolStripButtonBullets.Checked = document.queryCommandState("InsertUnorderedList");

                toolStripButtonLeft.Checked = document.queryCommandState("JustifyLeft");
                toolStripButtonCenter.Checked = document.queryCommandState("JustifyCenter");
                toolStripButtonRight.Checked = document.queryCommandState("JustifyRight");
                toolStripButtonFull.Checked = document.queryCommandState("JustifyFull");
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
            }
            finally
            {
                EndUpdate();
            }
        }


        /// <summary>
        /// 插入段落
        /// </summary>
        public void InsertParagraph()
        {
            webBrowserBody.Document.ExecCommand("InsertParagraph", false, null);
        }
        /// <summary>
        /// 插入水平线
        /// </summary>
        public void InsertBreak()
        {
            webBrowserBody.Document.ExecCommand("InsertHorizontalRule", false, null);
        }
        /// <summary>
        /// 选中文档所有内容.
        /// </summary>
        public void SelectAll()
        {
            webBrowserBody.Document.ExecCommand("SelectAll", false, null);
        }
        /// <summary>
        /// 回退最后一步操作
        /// </summary>
        public void Undo()
        {
            webBrowserBody.Document.ExecCommand("Undo", false, null);
        }
        /// <summary>
        /// 前进操作
        /// </summary>
        public void Redo()
        {
            webBrowserBody.Document.ExecCommand("Redo", false, null);
        }
        /// <summary>
        /// 剪切选中内容到剪贴板
        /// </summary>
        public void Cut()
        {
            webBrowserBody.Document.ExecCommand("Cut", false, null);
        }
        /// <summary>
        /// 从剪贴板粘贴内容到当前位置
        /// </summary>
        public void Paste()
        {
            webBrowserBody.Document.ExecCommand("Paste", false, null);
        }
        /// <summary>
        /// 复制选中内容到剪贴板
        /// </summary>
        public void Copy()
        {
            webBrowserBody.Document.ExecCommand("Copy", false, null);
        }


        private void m_timer_Tick(object sender, EventArgs e)
        {
            m_timer.Stop();
            DOC.designMode = "On";
            webBrowserBody.DocumentText = m_source;
            this.RefreshToolBar();
        }
        private void webBrowserBody_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (m_isEnterBR && e.KeyData == Keys.Enter)
            {
                //回车相当于 shift+enter以便输入<br>
                SendKeys.Send("{BS}");
                SendKeys.Send("+{ENTER}");
            }
            if (e.IsInputKey)
            {
                return;
            }
            RefreshToolBar();
        }
        private void webBrowserBody_DocumentClick(object sender, HtmlElementEventArgs e)
        {
            RefreshToolBar();
        }
        private void webBrowserBody_DocumentFocusing(object sender, HtmlElementEventArgs e)
        {
            RefreshToolBar();
        }
        private void webBrowserBody_GotFocus(object sender, EventArgs e)
        {
            //当获取焦点时，将焦点传递给文档的Body
            if (webBrowserBody.Document != null && webBrowserBody.Document.Body != null)
            {
                webBrowserBody.Document.Body.Focus();
            }
        }
        private void Document_ContextMenuShowing(object sender, HtmlElementEventArgs e)
        {
            if (this.ContextMenuStrip != null)
            {
                this.ContextMenuStrip.Show(webBrowserBody.PointToScreen(e.ClientMousePosition));
            }
            else if (m_allowContentMenu)
            {
                this.mnu_defaul.Show(webBrowserBody.PointToScreen(e.ClientMousePosition));
            }
        }

        #region Menu

        private void tmn_cut_Click(object sender, EventArgs e)
        {
            if (Updating) return;
            this.Cut();
        }
        private void tmn_copy_Click(object sender, EventArgs e)
        {
            if (Updating) return;
            this.Copy();
        }
        private void tmn_paste_Click(object sender, EventArgs e)
        {
            if (Updating) return;
            this.Paste();
        }
        private void tmn_delete_Click(object sender, EventArgs e)
        {
            if (Updating) return;
        }
        private void tmn_selectAll_Click(object sender, EventArgs e)
        {
            if (Updating) return;
            this.SelectAll();
        }

        #endregion

        #region Tool Bar

        private void toolStripComboBoxName_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("FontName", false, toolStripComboBoxName.Text);
        }
        private void toolStripComboBoxSize_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            int size = (toolStripComboBoxSize.SelectedItem == null) ? 1 : (toolStripComboBoxSize.SelectedItem as FontSize).ValueSize;
            webBrowserBody.Document.ExecCommand("FontSize", false, size);
        }
        private void toolStripButtonBold_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("Bold", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonItalic_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("Italic", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonUnderline_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("Underline", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonColor_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            int fontcolor = (int)((mshtml.IHTMLDocument2)webBrowserBody.Document.DomDocument).queryCommandValue("ForeColor");

            ColorDialog dialog = new ColorDialog();
            dialog.Color = Color.FromArgb(0xff, fontcolor & 0xff, (fontcolor >> 8) & 0xff, (fontcolor >> 16) & 0xff);

            DialogResult result = dialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                string color = dialog.Color.Name;
                if (!dialog.Color.IsNamedColor)
                {
                    color = "#" + color.Remove(0, 2);
                }

                webBrowserBody.Document.ExecCommand("ForeColor", false, color);
            }
            RefreshToolBar();
        }
        private void toolStripButtonBGColor_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            int fontbgcolor = (int)((mshtml.IHTMLDocument2)webBrowserBody.Document.DomDocument).queryCommandValue("BackColor");

            ColorDialog dialog = new ColorDialog();
            dialog.Color = Color.FromArgb(0xff, fontbgcolor & 0xff, (fontbgcolor >> 8) & 0xff, (fontbgcolor >> 16) & 0xff);

            DialogResult result = dialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                string color = dialog.Color.Name;
                if (!dialog.Color.IsNamedColor)
                {
                    color = "#" + color.Remove(0, 2);
                }

                webBrowserBody.Document.ExecCommand("BackColor", false, color);
            }
            RefreshToolBar();
        }

        private void toolStripButtonNumbers_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("InsertOrderedList", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonBullets_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("InsertUnorderedList", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonOutdent_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("Outdent", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonIndent_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("Indent", false, null);
            RefreshToolBar();
        }

        private void toolStripButtonLeft_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("JustifyLeft", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonCenter_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("JustifyCenter", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonRight_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("JustifyRight", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonFull_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("JustifyFull", false, null);
            RefreshToolBar();
        }

        private void toolStripButtonLine_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("InsertHorizontalRule", false, null);
            RefreshToolBar();
        }
        private void toolStripButtonHyperlink_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("CreateLink", true, null);
            RefreshToolBar();
        }
        private void toolStripButtonPicture_Click(object sender, EventArgs e)
        {
            if (Updating)
            {
                return;
            }

            webBrowserBody.Document.ExecCommand("InsertImage", true, null);
            RefreshToolBar();
        }

        #endregion

        #region Font Size

        /// <summary>
        /// 用于web的字体大小类
        /// </summary>
        private class FontSize
        {
            private FontSize(int displaySize, int valueSize)
            {
                m_displaySize = displaySize;
                m_valueSize = valueSize;
            }

            private static List<FontSize> m_allFontSize = null;
            private int m_displaySize;
            private int m_valueSize;

            /// <summary>
            /// 所有的字体大小集合
            /// </summary>
            public static List<FontSize> AllFontSize
            {
                get
                {
                    if (m_allFontSize == null)
                    {
                        m_allFontSize = new List<FontSize>();
                        m_allFontSize.Add(new FontSize(8, 1));
                        m_allFontSize.Add(new FontSize(10, 2));
                        m_allFontSize.Add(new FontSize(12, 3));
                        m_allFontSize.Add(new FontSize(14, 4));
                        m_allFontSize.Add(new FontSize(18, 5));
                        m_allFontSize.Add(new FontSize(24, 6));
                        m_allFontSize.Add(new FontSize(36, 7));
                    }

                    return m_allFontSize;
                }
            }
            /// <summary>
            /// web中使用的字体大小值
            /// </summary>
            public int ValueSize
            {
                get
                {
                    return m_valueSize;
                }
            }
            /// <summary>
            /// 显示的实际字体大小
            /// </summary>
            public int DisplaySize
            {
                get
                {
                    return m_displaySize;
                }
            }

            /// <summary>
            /// 根据字体大小值查找实例
            /// </summary>
            /// <param name="value"></param>
            /// <returns></returns>
            public static FontSize Find(int value)
            {
                if (value < 1)
                {
                    return AllFontSize[0];
                }

                if (value > 7)
                {
                    return AllFontSize[6];
                }

                return AllFontSize[value - 1];
            }

            public override string ToString()
            {
                return m_displaySize.ToString();
            }
        }

        #endregion

        #region ToolStripComboBox
        /// <summary>
        /// 扩展的下拉式工具项
        /// </summary>
        public class ToolStripComboBoxEx : ToolStripComboBox
        {
            public override Size GetPreferredSize(Size constrainingSize)
            {
                Size size = base.GetPreferredSize(constrainingSize);
                size.Width = Math.Max(Width, 0x20);
                return size;
            }
        }
        #endregion

        #region API

        public enum INTERNETFEATURELIST
        {
            FEATURE_OBJECT_CACHING = 0,
            FEATURE_ZONE_ELEVATION = 1,
            FEATURE_MIME_HANDLING = 2,
            FEATURE_MIME_SNIFFING = 3,
            FEATURE_WINDOW_RESTRICTIONS = 4,
            FEATURE_WEBOC_POPUPMANAGEMENT = 5,
            FEATURE_BEHAVIORS = 6,
            FEATURE_DISABLE_MK_PROTOCOL = 7,
            FEATURE_LOCALMACHINE_LOCKDOWN = 8,
            FEATURE_SECURITYBAND = 9,
            FEATURE_RESTRICT_ACTIVEXINSTALL = 10,
            FEATURE_VALIDATE_NAVIGATE_URL = 11,
            FEATURE_RESTRICT_FILEDOWNLOAD = 12,
            FEATURE_ADDON_MANAGEMENT = 13,
            FEATURE_PROTOCOL_LOCKDOWN = 14,
            FEATURE_HTTP_USERNAME_PASSWORD_DISABLE = 15,
            FEATURE_SAFE_BINDTOOBJECT = 16,
            FEATURE_UNC_SAVEDFILECHECK = 17,
            FEATURE_GET_URL_DOM_FILEPATH_UNENCODED = 18,
            FEATURE_TABBED_BROWSING = 19,
            FEATURE_SSLUX = 20,
            FEATURE_DISABLE_NAVIGATION_SOUNDS = 21,
            FEATURE_DISABLE_LEGACY_COMPRESSION = 22,
            FEATURE_FORCE_ADDR_AND_STATUS = 23,
            FEATURE_XMLHTTP = 24,
            FEATURE_DISABLE_TELNET_PROTOCOL = 25,
            FEATURE_FEEDS = 26,
            FEATURE_BLOCK_INPUT_PROMPTS = 27,
            FEATURE_ENTRY_COUNT = 28
        }

        private const int SET_FEATURE_ON_THREAD = 0x00000001;
        private const int SET_FEATURE_ON_PROCESS = 0x00000002;
        private const int SET_FEATURE_IN_REGISTRY = 0x00000004;
        private const int SET_FEATURE_ON_THREAD_LOCALMACHINE = 0x00000008;
        private const int SET_FEATURE_ON_THREAD_INTRANET = 0x00000010;
        private const int SET_FEATURE_ON_THREAD_TRUSTED = 0x00000020;
        private const int SET_FEATURE_ON_THREAD_INTERNET = 0x00000040;
        private const int SET_FEATURE_ON_THREAD_RESTRICTED = 0x00000080;

        [DllImport("urlmon.dll")]
        [PreserveSig]
        [return: MarshalAs(UnmanagedType.Error)]
        static extern int CoInternetSetFeatureEnabled(
             INTERNETFEATURELIST FeatureEntry,
             [MarshalAs(UnmanagedType.U4)] int dwFlags,
             bool fEnable);

        #endregion
    }
}
